Computers can be programmed to perform any suitable number of functions. Frequently, the computers are programmed to execute various functions with software components that interact to produce a result.
The software components may be initially stored in some form of nonvolatile memory, such as a hard disk. Nonvolatile memory can provide persistent storage for a large amount of computer software and data used in operating a computer. However, a conventional computer system traditionally does not execute software components directly from non-volatile memory. The non-volatile memory may be too slow to allow access to instructions and data as the computer operates.
Accordingly, a conventional computer may “load” software components before they are executed so that they can use fast memory. Frequently, some software is loaded each time a computer is powered up. However, not all software is loaded at power up. For example, a computer may be programmed with more software than is used at one time. Accordingly, it is known to dynamically load software components. These components are stored as a file containing computer executable instructions in a form that can be executed without compiling. These files also may be called “binaries” or “executables.”
Loading is done by a component of an operating system, called a “loader.” The loader performs multiple operations that are needed to make a binary ready for execution, including allocating fast memory to store computer-executable instructions that make up the binary. The loader may also trigger allocation of fast memory to store data accessed by the binary.
A binary may implement multiple functions, sometimes referred to as a library of functions. The functions implemented in a binary may be defined in an “interface contract.” The interface contract defines application programming interfaces (APIs) that can be used to access the functions in the library. The library may be said to “export” or “publish” that interface contract through an “export address table.” Other components may be said to “consume” or “import” the interface contract. Once the binary is loaded, the consuming components can access, or link to, all of the functions in the library by accessing the functions using interfaces defined in the interface contract. For this reason, a software component that is loaded in this fashion may be called a “dynamically linked library.”
Because the interface contract for a component is known in advance, components consuming the interface contract can be written using APIs defined by that contract so that they can interact with the library. Each dynamically linked library may include an import address table that identifies other dynamically linked libraries that it consumes, which are sometimes referred to as dependent dynamically linked libraries. When one dynamically linked library is loaded, a loader may be said to “resolve” the interface contracts between two binaries by matching the entries of one binary's import table to the exports of another binary's export table. Though, a loader may defer loading dependent binaries until a later time, such as when the dependent binaries are actually accessed, sometimes referred to as “delay loading.”
In some cases, an export table entry for a dynamically linked library may contain a pointer to the export of another dynamically linked library. This is sometimes referred to as a “forwarder” or a “forwarded export”. The loader resolves a forwarded export by reading the export address table of the binary in question and from that export table, retrieving the name and interface name of the binary pointed to by the export address table.